package com.yonyou.crm.common.http.aop;

import java.io.BufferedReader;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.dubbo.common.utils.IOUtils;
import com.yonyou.crm.common.rest.constant.HttpKeyConstant;
import com.yonyou.crm.common.security.util.HttpEncryptUtil;

@Aspect
@Component
public class EncryptAop {

	private final static Logger logger = LoggerFactory.getLogger(EncryptAop.class);
	private String[] fileURLs = { "tpub/excels" };
	
	@Pointcut("(execution(public * com.yonyou.crm.*.*.ctrl.*.*(..)) || execution(public * com.yonyou.crm.*.*.appctrl.*.*(..))) && !execution(* com.yonyou.crm.sys.defaul.ctrl.DefaultCtrl.*(..))")
    public void encryptAspect(){}

    @Before("encryptAspect()")
    public void before(JoinPoint jp) throws Exception{
    	
    	HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
		String paramStr = getParam(request);
		
		if (StringUtils.isNotBlank(paramStr)) {
			logger.info(">>>>>>>>>>");
			
			logger.info("请求方法：" + request.getMethod() + " " + "请求URL：" + request.getServletPath());
			logger.info("请求参数：" + paramStr);
		}
		
		request.setAttribute(HttpKeyConstant.RequestRootKey, paramStr);
    }
    
    @Around("encryptAspect()")
    public synchronized Object around(ProceedingJoinPoint jp) throws Throwable{
    	
		Object obj = jp.proceed();
		
		if (obj != null) {
			
			HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
			logger.info("<<<<<<<<<<");
			logger.info("请求方法：" + request.getMethod() + " " + "请求URL：" + request.getServletPath());
			logger.info("返回数据：" + JSONObject.fromObject(obj));
			
	    	//对返回值进行加密
	    	if (obj instanceof Map) {
	    		
	    		@SuppressWarnings("unchecked")
				Map<String, Object> dataMap = (Map<String, Object>) obj;
	    		if (dataMap != null && dataMap.containsKey(HttpKeyConstant.ResponseRootKey)) {
	 
	    			//文件请求不加密
	    			String contentType = request.getContentType();
	    			if (contentType != null && contentType.toLowerCase().startsWith("multipart/")) {
	    				dataMap.put(HttpKeyConstant.ResponseRootKey, dataMap.get(HttpKeyConstant.ResponseRootKey));
	    			}
	    			else {
	    				String dataStr = HttpEncryptUtil.desEncodeData(dataMap.get(HttpKeyConstant.ResponseRootKey));
		    			dataMap.put(HttpKeyConstant.ResponseRootKey, dataStr);
	    			}
	    		}
	    	}
		}

    	return obj;
    }
    
    /**
     * 获得解密请求参数
     * @param request
     * @return
     * @throws Exception
     */
	private String getParam(HttpServletRequest request) throws Exception{
		
		//文件请求
		String contentType = request.getContentType();
		if (contentType != null && contentType.toLowerCase().startsWith("multipart/")) {
			return "";
		}
		
		String paramStr = "";
		
		if("GET".equals(request.getMethod()) || "DELETE".equals(request.getMethod())) {
			paramStr = request.getParameter(HttpKeyConstant.RequestRootKey);
			
			//文件请求请求不加密
			if (isFileURL(request.getRequestURI())) {
				return paramStr;
			}
		}
		else {
			
			BufferedReader reader = new BufferedReader(request.getReader());
			String body = IOUtils.read(reader);
			if (StringUtils.isNotBlank(body)) {
				JSONObject bodyJson = JSONObject.fromObject(body);
				if (bodyJson.containsKey(HttpKeyConstant.RequestRootKey)) {
					paramStr = bodyJson.getString(HttpKeyConstant.RequestRootKey);
				}
			}

		}
		
		//解密请求参数
		return HttpEncryptUtil.desDecodeRequest(paramStr);
	}
	
	/**
	 * 是否文件url
	 * @param url
	 * @return
	 */
	private boolean isFileURL(String url) {
		
		if (StringUtils.isBlank(url)) {
			return false;
		}
		
		for (String fileURL : fileURLs) {
			if (url.contains(fileURL)) {
				return true;
			}
		}
		return false;
	}
	
}
